/*
 * Copyright (c) 2013-2018 上海汇数数据. All rights reserved.
 * @(#) AesCipherApi.java 2018-08-06 17:26
 */

package cn.jh.common.core.crypto;

import org.intellij.lang.annotations.MagicConstant;

import static com.google.common.base.Preconditions.checkArgument;


/**
 * 基于JCA体系的 `CipherApi` 接口的AES加密算法的实现。
 *
 * @author Fuchun
 * @since 1.0
 */
public class AesCipherApi extends BlockCipherApi {

    private static final String ALGORITHM = "AES";

    private static final AesCipherApi DEFAULT_API = new AesCipherApi(
            KeyBit.KB_256.bit, PaddingSchema.PKCS5);

    /**
     * `AesCipherApi` 的默认实例。基于以下配置：
     * <pre>
     * 1. `AES/CBC/PKCS5Padding`
     * 2. `keySize` 大小：256bit, 长度：32
     * 3. `IV` 大小：128bit, 长度：16；根据key生成固定的IV
     * 4. 不使用前置`IV` 填充原数据
     * </pre>
     */
    public static AesCipherApi getInstance() {
        return DEFAULT_API;
    }

    /**
     * 根据指定的算法参数，构造并返回一个新的 {@code AesCipherApi}。
     *
     * @param params 算法参数。
     * @return 指定算法参数的 {@code AesCipherApi}。
     * @throws IllegalArgumentException 如果算法参数设置错误。
     */
    public static AesCipherApi getInstance(SymmetricCipherParams params) {
        return new AesCipherApi(params);
    }

    /**
     * 构造并返回指定密钥大小的基于 {@code AES/CBC/PKCS5Padding} 转换的 {@code AesCipherApi}。
     *
     * @param keySize 密钥大小：128, 192, 256
     * @return 指定密钥大小的基于 {@code AES/CBC/PKCS5Padding} 转换的 {@code AesCipherApi}。
     */
    public static AesCipherApi getInstance(
            @MagicConstant(intValues = { 128, 192, 256 }) int keySize) {
        return new AesCipherApi(keySize, PaddingSchema.PKCS5);
    }

    private AesCipherApi(int keySize, PaddingSchema padding) {
        this(CipherParamsKt.aesBuilder()
                .setTransformation(Transformation.aesOf(padding))
                .setKeySize(keySize).build());
    }

    private AesCipherApi(SymmetricCipherParams params) {
        super(params);
    }

    @Override
    protected void initialize() {
        checkArgument(ALGORITHM.equals(params.getAlgorithm()),
                "The algorithm must be \"%s\".", ALGORITHM);
    }
}
